const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
console.log("My Promise");
const resolvePromise = (x, promise2, resolve, reject) => {
  // console.log('promise2', promise2); // Cannot access 'p2' before initialization
  // 用x 来决定promise 是成功还是失败
  // then 为什么是异步的，因为需要 process.nextTick
  // resolve(x);
  // promise 可以互通
  console.log(
    "%c [  ]-11",
    "font-size:13px; background:pink; color:#bf2c9f;",
    x
  );
  // x 总得做点什么，不然就是pending 状态，没法往下走了。自己等待自己完成
  if (x === promise2) {
    return reject(new TypeError("Chaining cycle detected for promise"));
  }
  // x 是一个对象/函数。有可能是promise
  if (
    (typeof x === "object" && typeof x !== "null") ||
    typeof x === "function"
  ) {
    // 看是否有then 方法
    try {
      let then = x.then;
      if (typeof then === "function") {
        then.call(
          x,
          (y, promise2, resolve, reject) => {
            resolvePromise(y, promise2, resolve, reject);
          },
          (r) => reject(r)
        );
      }
    } catch (error) {
      reject(error); // 取值出错
    }
  } else {
    // 普通值,直接向下传递
    resolve(x);
  }
};
class Promise {
  constructor(executor) {
    this.status = PENDING;
    this.value = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    const resolve = (value) => {
      // 如果传入的是一个promise
      if (value instanceof Promise) {
        // value.then 之后，return
        return value.then(resolve, reject);
      }
      //  确保状态 只能由 PENDING =》FULFILLED
      if (this.status === "PENDING") {
        this.status = FULFILLED;
        this.value = value;
        // 调用回调
        this.onFulfilledCallbacks.forEach((fn) => fn());
      }
    };
    const reject = (reason) => {
      //  确保状态 只能由 PENDING =》REJECTED
      if (this.status === "PENDING") {
        this.status = REJECTED;
        this.value = reason;
        // 调用回调
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  // 此时在 executor的立即执行下，resolve/reject 已经执行完毕，并且赋了相应的值，再调用then ，里面的回调，就是直接调用执行了，并传值。
  then(onFulfilled, onRejected) {
    // v=> v
    // 当 Promise 成功被解决时，它会将解析值作为参数传递给 onFulfilled 回调函数。这个回调函数可以选择对该值进行处理或返回新的值。
    // then 方法中如果没有传递参数，可以透传到下一个then中
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (r) => {
            throw r;
          };
    // 既然 new Promise 是立即执行，那我直接给你套进来,但是此时只能返回一个then，如果后面有很多then，怎么办？并且return的值，有特殊的怎么办？ 单独对resolve（x） 做一层处理
    let p2 = new Promise((resolve, reject) => {
      // 解决p2 拿不到的问题
      process.nextTick(() => {
        if (this.status === "FULFILLED") {
          try {
            let x = onFulfilled(this.value);
            // 看promise的值，要做具体特殊的处理
            resolvePromise(x, p2, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }
      });

      if (this.status === 'REJECTED') {
        process.nextTick(() => {
          try {
            let x = onRejected(this.value);
            resolvePromise(x, p2, resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      }
      // 如果是pending 状态，也就是异步状态，需要都塞到队列里。等到异步执行时，外部会直接调用resolve/reject,所以在resolve/reject 中，调用callback
      //
      if (this.status === "PENDING") {
        // 但是此时如果想要 知道 onFulfilled 的返回值 这里就不行了，所以包一层，包完还是一个函数，这里对value 也做处理了，再调用处，还要再执行一次
        // this.onFulfilledCallbacks.push(onFulfilled);
        // this.onRejectedCallbacks.push(onRejected);
        this.onFulfilledCallbacks.push(() => {
          process.nextTick(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(x, p2, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          process.nextTick(() => {
            try {
              let x = onRejected(this.value);
              resolvePromise(x, p2, resolve, reject);
            } catch (error) {
              reject(error);
            }
          });
        });
      }
      // 我们在这里先写一个测试，返回一个promise，但是要做到值的传递，怎么传？
      // let p2 = new Promise((resolve, reject) => {
      // resolve(x)
    });

    return p2;
  }
  // cache 就是then(null, (err)=>err)，用then 做还有一个好处：他会返回一个新的promise
  cache(errCallback) {
    return this.then(null, errCallback);
  }
  //进行清理工作或者资源释放等操作
  // 返回一个新的promise，确保在finally 后继续执行后续传递的结果。但是失败了怎么执行后面的结果？
  finally(callback) {
    this.then(
      (value) => {
        // 在 promise 函数 成功时执行，执行后续的
      },
      (reason) => {
        // 在 promise 函数 失败时执行，执行后续的
      }
    );
  }
}
// 会产生一个新的promise,如果传入的是一个promsie ，那还要 包一层吗
Promise.resolve = function (value) {
  return new Promise((resolve, reject) => {
    resolve(value);
  });
};
Promise.reject = function (reason) {
  return new Promise((resolve, reject) => {
    reject(reason);
  });
};


// promise.all 用于将多个promise 实例，该方法接收一个数组作为参数， 包装成一个新的实例，返回的也是一个数组。如果有一个失败，则返回失败的promsie
// 但是可能传入的不是一个数组，需要用 promise.resolve包装一下
// 这里就有两个问题： 怎么知道处理保证顺序，队列形式。怎么知道执行完毕，需要一个计数器，等计数器等于传进来数组的长度，代表执行完毕
// Promise.all = function (values) {
//   let idx = 0; // 
//   let result = [];
//   return new Promise((resolve, reject) => {
//     values.forEach((value, i) => {
//       Promise.resolve(value).then((res) => {
//         result[i] = res;
        
//         console.log('%c [  ]-186', 'font-size:13px; background:pink; color:#bf2c9f;', result)
//         // if (++idx === values.length) return result;
//         if (++idx === values.length)  return result;
//         // if (++idx === values.length)  resolve(result);
//       }, reject);
//     });
//   });
// };
Promise.all = function(promises){
  return new Promise((resolve,reject)=>{
    let values = [];
    let count  = 0
    if (promises.length === 0) return resolve([]);
    promises.forEach((item)=>{
      Promise.resolve(item).then((res)=>{
      values[count++] = res;
      if (++count === promises.length)  resolve(values);
      })
    },reject)
  })
}

Promise.race = function (values) {
  return new Promise((resolve, reject) => {
    values.forEach((value) => {
      Promise.resolve(value).then(resolve, reject);
    })
  })
}
// 
/**
  * 1. 传入一个函数，无论成功失败/失败 说明就是一个then方法。等待函数执行完，再走。返回的是一个。Promise.resolve 可以解析传入的promise，
  * 2. 无论成功失败/ 函数执行后的结果，都要等， Promise.resolve(fn).then
  * 3. .then 没有返回值 不停的return 才能永远then
  * 4. 一个promise 返回一个promise 才会有等待效果。作为下一次then 的结果
 */
Promise.prototype.finally = function(fn) {
  return this.then((val)=>{
    return Promise.resolve(fn().then(()=>val))
  },(r)=>{
    return Promise.resolve(fn().then(()=>{throw r}))
  })
}


module.exports = Promise;
